package domain

import (
	log "github.com/sirupsen/logrus"
	"usbipproxy/pb"
)

type MsgPipeRepo interface {
	RecvInMsg(msg *pb.ProxyMsg)
	SendOutMsg(msg *pb.ProxyMsg)
	RecvInMsgNonBlock(msg *pb.ProxyMsg)
	SendOutMsgNoBlock(msg *pb.ProxyMsg)
	CloseIn()
	GetOutMsg() chan *pb.ProxyMsg
	GetInMsg() chan *pb.ProxyMsg
}

type OpFunc func(pipe *MsgPipe)

func WithChannelNum(channelNum int) OpFunc {
	return func(pipe *MsgPipe) {
		pipe.channelNum = channelNum
	}
}

type MsgPipe struct {
	in, out    chan *pb.ProxyMsg
	channelNum int
}

func (pipe *MsgPipe) RecvInMsg(msg *pb.ProxyMsg) {
	select {
	case pipe.in <- msg:
		return
	}
	/*
		n := 0
		for {
			select {
			case pipe.in <- msg:
				return
			default:
				if n%1000 == 0 {
					n++
					log.Warnf("MsgPipe RecvInMsg channel full")
				}
				time.Sleep(time.Millisecond * 1)
			}
		}
	*/
}

func (pipe *MsgPipe) SendOutMsg(msg *pb.ProxyMsg) {
	select {
	case pipe.out <- msg:
		return
	}
	/*
		n := 0
		for {
			select {
			case pipe.out <- msg:
				return
			default:
				if n%1000 == 0 {
					n++
					log.Warnf("MsgPipe SendOutMsg channel full")
				}
				time.Sleep(time.Millisecond * 1)
			}
		}
	*/
}

func (pipe *MsgPipe) RecvInMsgNonBlock(msg *pb.ProxyMsg) {
	select {
	case pipe.in <- msg:
	default:
		log.Infof("pipe RecvInMsgNonBlock chan full")
	}

}

func (pipe *MsgPipe) SendOutMsgNoBlock(msg *pb.ProxyMsg) {
	select {
	case pipe.out <- msg:
	default:
		log.Infof("pipe SendOutMsgNoBlock chan full")
	}
}

func (pipe *MsgPipe) CloseIn() {
	close(pipe.in)
}

func (pipe *MsgPipe) GetOutMsg() chan *pb.ProxyMsg {
	return pipe.out
}

func (pipe *MsgPipe) GetInMsg() chan *pb.ProxyMsg {
	return pipe.in
}

func NewMsgPipe(opts ...OpFunc) MsgPipeRepo {
	pipe := &MsgPipe{}
	for _, opt := range opts {
		opt(pipe)
	}

	if pipe.channelNum <= 0 {
		pipe.channelNum = 60000
	}

	pipe.in = make(chan *pb.ProxyMsg, pipe.channelNum)
	pipe.out = make(chan *pb.ProxyMsg, pipe.channelNum)
	return pipe
}
